package com.spring.beans;

import com.spring.util.ReflectionUtils;

import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liyuncong
 * @version 1.0
 * @file BeanUtils
 * @brief BeanUtils
 * @details BeanUtils
 * @date 2023-02-22
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                        NAME               DESCRIPTION
 * 2023-02-22                  liyuncong          Created
 */
public abstract class BeanUtils {

    private static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES;

    static {
        Map<Class<?>, Object> values = new HashMap<>();
        values.put(boolean.class, false);
        values.put(byte.class, (byte) 0);
        values.put(short.class, (short) 0);
        values.put(int.class, 0);
        values.put(long.class, 0L);
        values.put(float.class, 0F);
        values.put(double.class, 0D);
        values.put(char.class, '\0');
        DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values);
    }

    public static <T> T instantiateClass(Constructor<T> constructor, Object... args)
        throws Exception {
        try {
            ReflectionUtils.makeAccessible(constructor);
            // kotlin detect not impl, just for java
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            Object[] argsWithDefaultValues = new Object[args.length];
            for (int i = 0; i < args.length; i++) {
                if (args[i] == null) {
                    Class<?> parameterType = parameterTypes[i];
                    argsWithDefaultValues[i] =
                        parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null;
                } else {
                    argsWithDefaultValues[i] = args[i];
                }
            }
            return constructor.newInstance(argsWithDefaultValues);
        } catch (Exception ex) {
            // TODO exception
            throw new RuntimeException("Instantiate Class exception.", ex);
        }
    }
}
